import type {
  AxiosInstance,
  AxiosRequestConfig,
  CancelTokenSource
} from 'axios'
import { DefaultPollConfig } from '@/constant'
import { deepMerge } from '@/utils'
import { isFunction } from '@/utils/is'
import { error } from '@/utils/log'
import TaskListMap from '@/taskListMap'
import EventTypeMap from '@/eventTypeMap'

export type EventType = string | symbol;

export interface Fn<T = any, R = T> {
  (...arg: T[]): R;
}

export type Nullable<T> = T | null;

export interface RequestConfig extends AxiosRequestConfig {
  cancelTokenSource?: CancelTokenSource
}

export interface CreateOptions {
  pollInterval?: number, // 轮询间隔时间
  pollCount?: number, // 轮询次数, 如果是 -1 则一致轮询
  delay?: number, // 延迟几秒后触发轮询
  axiosInstance?: Nullable<AxiosInstance>, // axios 实例
  reuse?: boolean,// 是否单独运行一个task 如果为 true 多次调用此事件类型 只会创建一个task
  requestConfig: RequestConfig,
  // retry?: number // api 请求失败后重试次数, 还没想到具体场景
}

/**
 * 轮询 API
 * @param eventType 事件类型
 * @param fn API 请求结束后(不论成功或者失败)回调函数
 * @param opt 选项参数
 */
const poll = (eventType: EventType, fn: Fn, opt?: CreateOptions) => {
  const cacheOptions = EventTypeMap.get(eventType)
  if (!opt && !cacheOptions) {
    error('请传递或者注册全局轮询参数')
    return
  }
  const options: CreateOptions = opt || cacheOptions!
  const { requestConfig } = options
  if (!isFunction(fn) || !eventType || !requestConfig) {
    error('eventType, fn, requestConfig必填')
    return
  }
  const baseOptions = deepMerge({}, DefaultPollConfig)
  let defaultOptions = deepMerge(baseOptions, options)
  if (defaultOptions.reuse) {
    defaultOptions = EventTypeMap.add(eventType, defaultOptions)
  }
  TaskListMap.add(eventType, fn, defaultOptions)
}

/**
 * 注册事件类型
 * @param eventType
 * @param opt
 * @returns
 */
const registerEventType = (eventType: EventType, opt: CreateOptions) => {
  if (!eventType || !opt) {
    return
  }
  EventTypeMap.add(eventType, opt)
}

const deleteEventType = (eventType: EventType) => {
  if (!eventType) {
    return
  }
  EventTypeMap.deleteEventType(eventType)
}

/**
 * 取消 当前 eventType 指定的函数 task 如果 task 正在执行则立即取消执行
 * @param eventType 事件类型
 * @param fn 回调
 */
const off = (eventType: EventType, fn: Fn) => {
  const taskList = TaskListMap.get(eventType)
  if (!taskList) {
    return
  }
  taskList.deleteTask(fn)
}

/**
 * 清除当前 eventType 下所有的 task
 * @param eventType 事件类型
 */
const clear = (eventType: EventType) => {
  const taskList = TaskListMap.get(eventType)
  if (!taskList) {
    return
  }
  taskList.clear()
}

/**
 * 销毁所有的 eventType 以及 eventType 下的 task
 */
const destroy = () => {
  TaskListMap.clear()
  EventTypeMap.clear()
}

export default {
  poll,
  off,
  clear,
  destroy,
  registerEventType,
  deleteEventType
}
